<?php
declare(strict_types=1);

namespace App;

class Server implements ServerInterface
{
    protected readonly App $app;

    protected array $servers = []; // 保存所有端口

    protected \Swoole\Server $server;

    public function __construct(App $app)
    {
        $this->app = $app;
    }

    public function start(): void
    {
        $serverConfig = $this->app->config->get('server');
        foreach ($serverConfig['server'] as $index => $config) {
            if ($index === 0) {
                $server = $this->getSwitchTypeServer($config);
                $this->server = $server;
                array_walk($serverConfig['callbacks'], function ($value, $key) use ($server) {
                    $server->on($key, [new $value, 'handle']);
                });
            } else {
                // 这里只有主线程才能执行 估计是就是swoole官方的bug
                $server = Runtime::isMainThread()
                    ? $this->server->addListener($config['host'], $config['port'], $config['sock_type'])
                    : $this->getServer($config['port']);
            }
            $server->set($serverConfig['settings'] + $config['settings']);

            array_walk($config['callbacks'], function ($value, $key) use ($server) {
                $server->on($key, [new $value, 'handle']);
            });

            //如果不是主线程 就不用执行了
            Runtime::isMainThread() && printf("%s Server start at %s:%d\n", $this->getServetType($config['sock_type']), $config['host'], $config['port']);

        }
        $this->server->start();
    }

    public function getServer(int $port = null): \Swoole\Server|\Swoole\Server\Port|null
    {
        if (is_null($port)) {
            return $this->server;
        }
        // 初始化
        empty($this->servers) && array_walk($this->server->ports, function (\Swoole\Server\Port $port) {
            $this->servers[$port->port] = $port;
        });
        return $this->servers[$port] ?? null;
    }

    protected function getSwitchTypeServer(array $config): \Swoole\Server
    {
        switch ($config['sock_type']) {
            case self::HTTP_SERVER:
                return new \Swoole\Http\Server($config['host'], $config['port'], SWOOLE_THREAD);
            case self::WEBSOCKET_SERVER:
                return new \Swoole\WebSocket\Server($config['host'], $config['port'], SWOOLE_THREAD);
            default:
                return new \Swoole\Server($config['host'], $config['port'], SWOOLE_THREAD, $config['sock_type']);
        }
    }


    protected function getServetType(int $sockType): string
    {
        return match ($sockType) {
            static::HTTP_SERVER => 'http',
            static::WEBSOCKET_SERVER => 'websocket',
            SWOOLE_SOCK_TCP => 'tcp',
            SWOOLE_SOCK_UDP => 'udp',
            SWOOLE_SOCK_TCP6 => 'tcp6',
            SWOOLE_SOCK_UDP6 => 'udp6',
            SWOOLE_SOCK_UNIX_DGRAM => 'unix-dgram',
            SWOOLE_SOCK_UNIX_STREAM => 'unix-stream',
            default => 'unknown',
        };
    }
}